﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Dynamic;
using System.ComponentModel.Composition;
using System.Threading;
using GT;
using System.ComponentModel.Composition.Hosting;
using System.Diagnostics;

namespace GT.Plugins
{
    [Export]
    public abstract class Plugin
    {
        static void Import(object[] hosts, string pluginPath)
        {
            var catalog = new DirectoryCatalog(pluginPath);
            var container = new CompositionContainer(catalog);
            try
            {
                container.ComposeParts(hosts);
            }
            catch (ChangeRejectedException ex)
            {
                Debug.Print(ex.Message);
            }
        }

        public abstract Plugin Host { get; set; }
        public abstract IEnumerable<string> GetFunctionNames();
        public abstract object Exec(string funcName, object arguments);

        public void ExecAsync(string funcName, object arguments)
        {
            ThreadPool.QueueUserWorkItem(DoExec, new { FuncName = funcName, Arguments = arguments, OnComplete = new Action<object>(delegate(object temp) { }), OnError = new Action<object>(delegate(object temp) { }) });
        }

        public void ExecAsync(string funcName, object arguments, Action<object> onComplete)
        {
            ThreadPool.QueueUserWorkItem(DoExec, new { FuncName = funcName, Arguments = arguments, OnComplete = onComplete, OnError = new Action<object>( delegate(object temp) { }) });
        }

        public void ExecAsync(string funcName, object arguments, Action<object> onComplete, Action<object> onError)
        {
            ThreadPool.QueueUserWorkItem(DoExec, new { FuncName = funcName, Arguments = arguments, OnComplete = onComplete, OnError = onError });
        }

        private void DoExec(object state)
        {
            dynamic args = state;
            Action<object> OnComplete = args.OnComplete;
            Action<object> OnError = args.OnError;
            object ret;
            try
            {
                ret = Exec(args.FuncName, args.Arguments);
                OnComplete.Raise(new object[] { ret });
            }
            catch (Exception ex)
            {
                OnError.Raise(new object[] { ex });
            }

        }
    }
}
